/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.commons.exception;

import io.iec.edp.caf.commons.exception.core.ExceptionUtility;
import lombok.Data;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.UUID;

/**
 * CAF运行时异常基类
 *
 * @author wangyandong
 */
@Data
public class CAFRuntimeException extends RuntimeException implements Serializable {

    private static final long serialVersionUID = 2423367815131409680L;

    /**
     * 异常的唯一标识
     */
    private String id;

    /**
     * 异常编号
     */
    private String exceptionCode;

    /**
     * 异常级别
     */
    private ExceptionLevel level;

    /**
     * 是否业务异常
     */
    private boolean bizException;

    /**
     * 异常消息
     */
    private String message;

    /**
     * 异常消息中的参数
     */
    private String[] messageParams;

    /**
     * 服务单元编号
     */
    private String serviceUnitCode;

    /**
     * 国际化提示信息
     */
    private String i18nMessage = "";

    /**
     * 资源文件
     */
    private String resourceFile;

    /**
     * 扩展的消息
     */
    private HashMap<String, String> extensionMessage;

    public CAFRuntimeException(String serviceUnitCode, String resourceFile, String exceptionCode, String[] messageParams, Exception innerException) {
        this(serviceUnitCode, resourceFile, exceptionCode, messageParams, (Throwable) innerException);
    }

    public CAFRuntimeException(String serviceUnitCode, String resourceFile, String exceptionCode, String[] messageParams, Throwable innerException) {
        this(serviceUnitCode, resourceFile, exceptionCode, messageParams, innerException, ExceptionLevel.Error, true, null);
    }

    public CAFRuntimeException(String serviceUnitCode, String resourceFile, String exceptionCode, String[] messageParams, Exception innerException, ExceptionLevel level) {
        this(serviceUnitCode, resourceFile, exceptionCode, messageParams, (Throwable) innerException, level);
    }

    public CAFRuntimeException(String serviceUnitCode, String resourceFile, String exceptionCode, String[] messageParams, Throwable innerException, ExceptionLevel level) {
        this(serviceUnitCode, resourceFile, exceptionCode, messageParams, innerException, level, true, null);
    }

    public CAFRuntimeException(String serviceUnitCode, String resourceFile, String exceptionCode, String[] messageParams, Exception innerException, ExceptionLevel level, boolean bizException) {
        this(serviceUnitCode, resourceFile, exceptionCode, messageParams, (Throwable) innerException, level, bizException);
    }

    public CAFRuntimeException(String serviceUnitCode, String resourceFile, String exceptionCode, String[] messageParams, Throwable innerException, ExceptionLevel level, boolean bizException) {
        this(serviceUnitCode, resourceFile, exceptionCode, messageParams, innerException, level, bizException, null);
    }

    public CAFRuntimeException(String serviceUnitCode, String resourceFile, String exceptionCode, String[] messageParams, Exception innerException, ExceptionLevel level, boolean bizException, HashMap<String, String> extensionMessage) {
        this(serviceUnitCode, resourceFile, exceptionCode, messageParams, (Throwable) innerException, level, bizException, extensionMessage);
    }

    /**
     * CAFRuntimeException构造器(resourceFile)
     *
     * @param serviceUnitCode  服务单元编号
     * @param resourceFile     资源文件
     * @param exceptionCode    异常编号
     * @param messageParams    提示消息的上下文参数
     * @param innerException   内部异常
     * @param level            异常级别
     * @param bizException     是否业务异常
     * @param extensionMessage 扩展信息
     */
    public CAFRuntimeException(String serviceUnitCode, String resourceFile, String exceptionCode, String[] messageParams, Throwable innerException, ExceptionLevel level, boolean bizException, HashMap<String, String> extensionMessage) {
        super(exceptionCode, innerException);
        if (innerException instanceof CAFRuntimeException) {
            this.id = ((CAFRuntimeException) innerException).getId();
        } else {
            this.id = UUID.randomUUID().toString();
        }
        this.serviceUnitCode = serviceUnitCode;
        this.resourceFile = resourceFile;
        this.exceptionCode = exceptionCode;
        this.messageParams = messageParams;

        this.level = level;
        this.bizException = bizException;
        this.extensionMessage = extensionMessage;
    }

    public CAFRuntimeException(String serviceUnitCode, String exceptionCode, String message, Exception innerException) {
        this(serviceUnitCode, exceptionCode, message, (Throwable) innerException);
    }

    public CAFRuntimeException(String serviceUnitCode, String exceptionCode, String message, Throwable innerException) {
        this(serviceUnitCode, exceptionCode, message, innerException, ExceptionLevel.Error, true, null);
    }

    public CAFRuntimeException(String serviceUnitCode, String exceptionCode, String message, Exception innerException, ExceptionLevel level) {
        this(serviceUnitCode, exceptionCode, message, (Throwable) innerException, level);
    }

    public CAFRuntimeException(String serviceUnitCode, String exceptionCode, String message, Throwable innerException, ExceptionLevel level) {
        this(serviceUnitCode, exceptionCode, message, innerException, level, true, null);
    }

    public CAFRuntimeException(String serviceUnitCode, String exceptionCode, String message, Exception innerException, ExceptionLevel level, boolean bizException) {
        this(serviceUnitCode, exceptionCode, message, (Throwable) innerException, level, bizException);
    }

    public CAFRuntimeException(String serviceUnitCode, String exceptionCode, String message, Throwable innerException, ExceptionLevel level, boolean bizException) {
        this(serviceUnitCode, exceptionCode, message, innerException, level, bizException, null);
    }

    public CAFRuntimeException(String serviceUnitCode, String exceptionCode, String message, Exception innerException, ExceptionLevel level, boolean bizException, HashMap<String, String> extensionMessage) {
        this(serviceUnitCode, exceptionCode, message, (Throwable) innerException, level, bizException, extensionMessage);
    }

    /**
     * CAFRuntimeException构造器(message)
     *
     * @param serviceUnitCode  服务单元编号
     * @param exceptionCode    异常编号
     * @param message          异常信息
     * @param innerException   内部异常
     * @param level            异常级别
     * @param bizException     是否业务异常
     * @param extensionMessage 扩展信息
     */
    public CAFRuntimeException(String serviceUnitCode, String exceptionCode, String message, Throwable innerException, ExceptionLevel level, boolean bizException, HashMap<String, String> extensionMessage) {
        super(message, innerException);
        //不处理baseException
//        if (innerException instanceof BaseException) {
//            this.id = ((BaseException) innerException).getId();
//        } else {
        this.id = UUID.randomUUID().toString();

        this.serviceUnitCode = serviceUnitCode;
        this.exceptionCode = exceptionCode;
        this.message = message;

        this.level = level;
        this.bizException = bizException;
        this.extensionMessage = extensionMessage;
    }

    /**
     * 重写了Message的获取方法
     *
     * @return 异常信息
     */
    @Override
    public String getMessage() {
        if ("".equals(getLocalizedMessage())) {
            return super.getMessage();
        } else {
            return getLocalizedMessage();
        }
    }

    public String getI18nMessage() {
        return getMessage();
    }

    @Override
    public String getLocalizedMessage() {
        if (!"".equals(this.i18nMessage)) {
            return this.i18nMessage;
        }

        //获取异常信息
        String messageStr = "";
        if ((this.message == null || "".equals(this.message)) && !"".equals(this.exceptionCode)) {
            messageStr = ExceptionUtility.getExceptionMessage(this.resourceFile, this.exceptionCode, this.serviceUnitCode);
        } else {
            messageStr = ExceptionUtility.getExceptionMessage(this.resourceFile, this.message, this.serviceUnitCode);
        }

        //如果数组不为空，则进行变量替换
        if (this.messageParams != null && messageStr != null) {
            //MessageFormat格式化
            String temp = messageStr;
            try {
                messageStr = MessageFormat.format(messageStr, this.messageParams);

                //MessageFormat格式化未成功进行String.format
                if (temp.equals(messageStr))
                    messageStr = String.format(messageStr, this.messageParams);
            } catch (Exception e) {
                messageStr = temp;
            }
        }
        this.i18nMessage = messageStr;
        return this.i18nMessage;
    }

}